home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1997 / HAM Radio 1997.iso / vcls / fbuf / filebuff.pas < prev    next >
Pascal/Delphi Source File  |  1996-04-08  |  22KB  |  627 lines

  1. unit FileBuff;
  2. {
  3.    Project "Opnek Libraries"
  4.    Copyright ⌐ 1995 Opnek Research.  All Rights Reserved.
  5.  
  6.    SUBSYSTEM:      Opnek Standard Libraries
  7.    TEST STUB:      Test stub included
  8.    FILE:           FileBuff.Pas
  9.    AUTHOR:         Jay Cole
  10.    WRITTEN:        05/10/95
  11.    LAST ASSERT:    19 <- Unique Assert code start here w/ new asserts.
  12.                                                                                
  13.    OVERVIEW                                                                    
  14.    ========                                                                    
  15.    Delphi provides no direct file buffer support, so I have invented a little
  16.    set of routines to allow full buffering up to 64k worth of buffer space.  
  17.    The routines pretty much mirror the delphi assignfile(), reset(), blockread->
  18.    Read() and blockWrite->write().  The system will re-raise exceptions as the 
  19.    it processes.  You can use the typical try ... except ... end block to catch
  20.    any problems that might occur.  Replacement for the TBufStream now missing
  21.    from BP 7.0, too bad.
  22.  
  23.    CAUTIONS
  24.    ========
  25.    This routine works poorely when trying to go backwards seeking through a file
  26.    you will get worse performance than straight reads.
  27.  
  28.    SUGGESTED ENHANCEMENTS
  29.    ======================
  30.    - Change to Windows read/write routines or assember routines which ever is 
  31.      faster.
  32.    - Add Read/Only open to the system.
  33.    - Provide a more accurate FileSize() method.
  34.  
  35.    UPDATE HISTORY
  36.    ==============
  37.    05/10/95 - Created initial object.
  38.    05/13/95 - Added logic for record size spanning 2 or more buffers.
  39.    05/20/95 - Fixed reading across spanned buffers.
  40. }
  41. interface
  42. {$define _TESTHARNESS} { directive ($) in for test harness inclusion }
  43.  
  44. { Externally used types and classes }
  45. type
  46.    TMemBuffer = array[0..65534] of char;
  47.    PMemBuffer = ^TMemBuffer;
  48.  
  49.    TBufferedFile = class(TObject)
  50.    private
  51.       { Memory buffer information }
  52.       buffer : PMemBuffer;
  53.       bufferSize,
  54.       bufferEnd : word;
  55.       bufferFilePos,
  56.       bufferOffset : longint; {<- Handle 64k wrap problems by using longint type }
  57.  
  58.       { file information }
  59.       fileName : string;
  60.       fileHandle : File;
  61.  
  62.       { File conditionals }
  63.       isOpen, dirtyBuffer : boolean;
  64.  
  65.       procedure LoadBuffer;
  66.       procedure DumpBuffer;
  67.  
  68.    public
  69.       constructor Create(const afileName : string; bufSize : word);
  70.       destructor Destroy; override;
  71.  
  72.       procedure AssignFile(const afileName : string);
  73.       procedure Reset;
  74.       procedure Rewrite;
  75.       procedure Close;
  76.  
  77.       function Eof : boolean;
  78.       function FilePos : longint;
  79.       function FileSize : longint;
  80.       procedure Seek(const offset : longint);
  81.  
  82.       procedure Read(var contents; const numBytes : word; var bytesRead : word);
  83.       procedure Write(var contents; const numBytes : word; var bytesWrote : word);
  84.    end;
  85.  
  86.    { Export the TestFileBuff test harness only if test harness is needed }
  87.    {$ifdef _TESTHARNESS} 
  88.       procedure TestFileBuff(
  89.                   bufsize, recsize : word;
  90.                   numiterations : longint;            
  91.                   var oldCreateTime, oldCopyTime, oldReadTime, oldModifyTime : double;
  92.                   var newCreateTime, newCopyTime, newReadTime, newModifyTime : double;
  93.                   var benchWrite, benchRead : double
  94.       ); 
  95.    {$endif}
  96.    
  97.  
  98. implementation
  99. uses Asserts, SysUtils; {<- Remember define _NDEBUG to remove slow Assert code }
  100.  
  101. { -- Public routines -- }
  102.  
  103. { (Final) Create a buffer file at this point, if a filename is supplied         }
  104. { other than '', the filename will be assigned, but the file will not be opened }
  105. { until the call to reset is made.  Note all files are opened as 1 byte binary  }
  106. { files.                                                                        }
  107. constructor TBufferedFile.Create(const afileName : string; bufSize : word);
  108. begin
  109.    { Call inherited constructor }
  110.    inherited Create;
  111.  
  112.    { init all the local variables passed by create method }
  113.    {$ifndef _NDEBUG} Assert(bufSize > 0, 'Invalid BufferSize', 1); {$endif}
  114.    bufferSize  := bufSize;
  115.    fileName    := afileName;
  116.    if (fileName <> '') then AssignFile(afileName);
  117.  
  118.    { boolean conditionals }
  119.    dirtyBuffer := true; 
  120.    isOpen := false; 
  121.  
  122.    { Other buffering positioning, the buffer file position, the offset in the   }
  123.    { current buffer and the amount of bytes in the buffer, for end of file      }
  124.    { conditions                                                                 }
  125.    bufferFilePos := 0;
  126.    bufferOffset := 0;
  127.    bufferEnd := 0;
  128.  
  129.    { Try to get our block of buffer memory, handle the problem and re-raise the }
  130.    { exception to the calling application, they can determine on how to handle  }
  131.    { it.                                                                        }
  132.    try
  133.       Getmem(buffer, bufferSize);
  134.    except
  135.       on EOutOfMemory do begin
  136.          buffer := nil;
  137.          raise;
  138.       end;
  139.    end;
  140. end;
  141.  
  142.  
  143. { (Final) Free up all the buffer space, assert the user has closed the file first }
  144. destructor TBufferedFile.Destroy;
  145. begin
  146.    {$ifndef _NDEBUG} Assert(not isOpen, 'Freeing a closed file', 2); {$endif}
  147.    if (buffer <> nil) then Freemem(buffer, bufferSize);
  148.    inherited Destroy;
  149. end;
  150.  
  151.  
  152. { (Final) Just like Delphi's current AssignFile procedure, only no file handle needed }
  153. procedure TBufferedFile.AssignFile(const afileName : string);
  154. begin
  155.    {$ifndef _NDEBUG} Assert(afileName <> '', 'Can''t assign blank file', 3); {$endif}
  156.    {$ifndef _NDEBUG} Assert(not isOpen, 'Re-assigning an open file', 4); {$endif}
  157.    fileName:= afileName;
  158.    System.Assign(fileHandle, fileName);
  159. end;
  160.  
  161.  
  162. { (Final) Create a file that doesn't exist, or overwrite and existing file }
  163. procedure TBufferedFile.Rewrite;
  164. begin
  165.    {$ifndef _NDEBUG} Assert(not isOpen, 'Rewrite called on an already open file', 5); {$endif}
  166.    {$ifndef _NDEBUG} Assert(fileName <> '', 'No filename assigned yet', 6); {$endif}
  167.    if (not isOpen) then begin
  168.       try
  169.          System.Rewrite(fileHandle, 1);
  170.       except
  171.          on EInOutError do begin
  172.             { Problem rewriting file, raise the exception up to caller }
  173.             isOpen := false;
  174.             raise;
  175.          end;
  176.       end;
  177.  
  178.       { Set up the buffering variables and set state to open }
  179.       bufferEnd := 0;
  180.       bufferFilePos := 0;
  181.       bufferOffset := 0;
  182.       isOpen := true;
  183.    end;
  184. end;
  185.  
  186.  
  187. { (Final) Reset the file in the ,1 mode for binary access.  setup the system for }
  188. { buffered access to the system                                                  }
  189. Procedure TBufferedFile.Reset;
  190. begin
  191.    {$ifndef _NDEBUG} Assert(not isOpen, 'Reset called on an already open file', 7); {$endif}
  192.    {$ifndef _NDEBUG} Assert(fileName <> '', 'No filename assigned yet', 8); {$endif}
  193.    if not isOpen then begin
  194.       try
  195.          System.Reset(fileHandle, 1);
  196.       except
  197.          on EInOutError do begin
  198.             { Can't find or open file, re-raise exception up }
  199.             isOpen := false;
  200.             raise;
  201.          end;
  202.       end;
  203.  
  204.       { Now, set up our buffer w/ the beginning of the file info }
  205.       bufferFilePos := 0; 
  206.       bufferOffset := 0; 
  207.       bufferEnd := 0;
  208.       isOpen := true;
  209.       LoadBuffer;
  210.    end;
  211. end;
  212.  
  213.  
  214. { (Final) Close out the file, and flush any outstanding buffer information }
  215. procedure TBufferedFile.Close;
  216. begin
  217.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 9); {$endif}
  218.    { First, flush buffer if necessary }          
  219.    if dirtyBuffer then 
  220.       DumpBuffer;
  221.  
  222.    { Close out the file and return to the user }
  223.    try
  224.       System.Close(fileHandle);
  225.    except
  226.       on EInOutError do raise;
  227.    end;
  228.    isOpen := false;
  229. end;
  230.  
  231.  
  232. { (Final) First of several file information procedures, returns the size of the }
  233. { currently opened file.  Remember, this routine can cause irratic results if   }
  234. { you call it before a buffer is flushed out fully.  There could be partial file}
  235. { data still in memory.                                                         } 
  236. function TBufferedFile.FileSize : longint;
  237. begin
  238.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 10); {$endif}
  239.    FileSize := System.FileSize(fileHandle);
  240. end;
  241.  
  242. { (coded) Return the file position in the current file }
  243. function TBufferedFile.FilePos : longint;
  244. begin
  245.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 11); {$endif}
  246.    FilePos := bufferFilePos + bufferOffset;
  247. end;
  248.  
  249. { (Final) Are we at the end of the buffer? }
  250. function TBufferedFile.Eof : boolean;
  251. begin
  252.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 12); {$endif}
  253.    Eof := FilePos >= FileSize;
  254. end;
  255.  
  256.  
  257. { (Tested) Read and write routines, first the read a set of bytes either from the}
  258. { buffer or from the file after a buffer reload handle record size spanning      }
  259. { multiple records                                                               }
  260. procedure TBufferedFile.Read(var contents; const numBytes : word; var bytesRead : word);
  261. var toReadLeft, outPos, currBufferBytesLeft : word;
  262. begin
  263.    bytesRead := 0;
  264.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 13); {$endif}
  265.    {$ifndef _NDEBUG} Assert(numBytes > 0, 'Can''t read 0 bytes', 14); {$endif}
  266.    if (bufferOffset + longint(numBytes) <= longint(bufferEnd)) then begin
  267.       { We are within the buffer boundary completely, simply a mem move }
  268.       Move(buffer^[bufferOffset], contents, numBytes);
  269.       inc(bufferOffset, numBytes);
  270.       bytesRead := numBytes;
  271.    end else begin
  272.       { The amount we need to read straddles a buffer boundary, we need to }
  273.       { read in two or more chunks.                                        }
  274.       try
  275.          { Read the end of the first buffer/check for EOF condition }
  276.          currBufferBytesLeft := bufferEnd - bufferOffset;      
  277.          if (bufferEnd = 0) then exit;
  278.          if (currBufferBytesLeft > 0) then 
  279.             Move(buffer^[bufferOffset], contents, currBufferBytesLeft);
  280.          bytesRead := currBufferBytesLeft;
  281.          toReadLeft := numBytes - currBufferBytesLeft;
  282.          outPos := currBufferBytesLeft;
  283.  
  284.          { Now, reload the next buffer and fill in the remaining bytes }
  285.          repeat 
  286.             { Any changes outstanding }
  287.             if (dirtyBuffer) then 
  288.                DumpBuffer;
  289.  
  290.             { Check for end of file and break if necessary }
  291.             inc(bufferFilePos, bufferEnd);
  292.             LoadBuffer;
  293.  
  294.             { Handle a read past eof() condition }
  295.             if (toReadLeft <=  bufferEnd) then begin
  296.                { Not at end-of-file, process normally }
  297.                Move(buffer^[bufferOffset], TMemBuffer(contents)[outPos], toReadLeft);
  298.                inc(bytesRead, toReadLeft);
  299.                inc(bufferOffset, toReadLeft);
  300.                toReadLeft := 0;
  301.             end else begin
  302.                { at the end of file, only read what is left, and return if 0 }
  303.                if (bufferEnd > 0) then begin
  304.                   Move(buffer^[bufferOffset], TMemBuffer(contents)[outPos], bufferEnd);
  305.                   inc(outPos, bufferEnd);
  306.                   inc(bufferOffset, bufferEnd);
  307.                end else                     
  308.                   exit;
  309.  
  310.                { We still have more reads, increment the dest index and dec bytes left }
  311.                { to read.                                                              }
  312.                inc(outPos, bufferEnd);
  313.                inc(bytesRead, bufferEnd);
  314.                dec(toReadLeft, bufferEnd);
  315.             end;
  316.          until toReadLeft = 0;
  317.       except
  318.          on EInOutError do begin
  319.             bytesRead := 0;
  320.             raise;
  321.          end;
  322.       end;
  323.    end;
  324. end;
  325.  
  326.  
  327. { (Tested) Write routine, just like the read routine, either a memory hit or bufsize}
  328. { disk hit.  Write the contents of the passed variable                              }
  329. procedure TBufferedFile.Write(var contents; const numBytes : word; var bytesWrote : word);
  330. var toWriteLeft, outPos, currBufferBytesLeft : word;
  331. begin
  332.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 15); {$endif}
  333.    {$ifndef _NDEBUG} Assert(numBytes > 0, 'Can''t write 0 bytes', 16); {$endif}
  334.  
  335.    { Mark the buffer as modified/dirty and then write the information out }
  336.    dirtyBuffer := true;
  337.    if (bufferOffset + longint(numBytes) <= longint(bufferSize)) then begin
  338.       { We are within the buffer boundary completely, simply a mem move in }
  339.       Move(contents, buffer^[bufferOffset], numBytes);
  340.       inc(bufferOffset, numBytes);
  341.       bytesWrote := numBytes;
  342.  
  343.       { Did we simply expand the size of the file, if so, increment bufferEnd }
  344.       { accordingly.                                                          }
  345.       if (bufferOffset > bufferEnd) then 
  346.          bufferEnd := bufferOffset;
  347.    end else begin
  348.       { The amount we need to read straddles a buffer boundary, we need to }
  349.       { write in two chunks.                                               }
  350.       try
  351.          { Read the end of the first buffer }
  352.          currBufferBytesLeft := bufferSize - bufferOffset;      
  353.          if (currBufferBytesLeft > 0) then 
  354.             Move(contents, buffer^[bufferOffset], currBufferBytesLeft);
  355.          bytesWrote := currBufferBytesLeft;
  356.          toWriteLeft := numBytes - currBufferBytesLeft;
  357.          outPos := currBufferBytesLeft;
  358.          bufferEnd := bufferSize;
  359.  
  360.          { Now, reload the next buffer(s) and fill in the remaining bytes  }
  361.          { could span multiple buffers in the worse case                   }
  362.          repeat
  363.             DumpBuffer;
  364.             inc(bufferFilePos, bufferSize);
  365.             LoadBuffer;
  366.  
  367.             { Handle a read past eof() condition }
  368.             if (toWriteLeft <=  bufferSize) then begin
  369.                { Not at end-of-file, process normally }
  370.                Move(TMemBuffer(contents)[outPos], buffer^[bufferOffset], toWriteLeft);
  371.                inc(bytesWrote, toWriteLeft);
  372.                inc(bufferOffset, toWriteLeft);
  373.                if (bufferOffset > bufferEnd) then bufferEnd := bufferOffset;
  374.                toWriteLeft := 0;
  375.             end else begin
  376.                { at the end of file, only read what is left }
  377.                Move(TMemBuffer(contents)[outPos],buffer^[bufferOffset], bufferSize);
  378.                bufferEnd := bufferSize;
  379.                inc(bytesWrote, bufferSize);
  380.                inc(outPos, bufferSize);
  381.                dec(toWriteLeft, bufferSize);
  382.             end;
  383.          until toWriteLeft = 0;
  384.          dirtyBuffer := true;
  385.       except     
  386.          on EInOutError do begin
  387.             bytesWrote := 0;
  388.             raise;
  389.          end;
  390.       end;
  391.    end;
  392. end;
  393.  
  394.  
  395. { (Final) Seek to a file position, if it is in the buffer, merely adjust the offset }
  396. procedure TBufferedFile.Seek(const offset : longint);
  397. begin
  398.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 17); {$endif}
  399.    { Are we even in the right ball park to read from memory }
  400.    if (offset >= bufferFilePos) and (offset < bufferFilePos + bufferEnd) then begin
  401.       bufferOffset := offset - bufferFilePos;
  402.    end else begin
  403.       { We are out of buffer range, flush any changes and then reload the  }
  404.       { appropriate buffer range                                           }
  405.       if (dirtyBuffer) then 
  406.          DumpBuffer;
  407.       bufferFilePos := offset;
  408.       try
  409.          LoadBuffer;
  410.       except
  411.          on EInOutError do raise;
  412.       end;
  413.    end;
  414. end;
  415.  
  416.  
  417.  
  418. { -- Private routines -- }
  419.  
  420. { (Final) Load up the buffer with as much data as allowed, this way reads/writes }
  421. { will go against our buffer memory.                                             }
  422. Procedure TBufferedFile.LoadBuffer;
  423. begin
  424.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 18); {$endif}
  425.    { Let's seek to the appropriate place and fill the buffer }
  426.    try
  427.       System.Seek(fileHandle, bufferFilePos);
  428.       System.BlockRead(fileHandle, buffer^, bufferSize, BufferEnd);
  429.       bufferOffset := 0;
  430.    except
  431.       on EInOutError do raise;
  432.    end;
  433.    dirtyBuffer := false;
  434. end;
  435.  
  436.  
  437. { (Final) There have been changes to buffer probably, so a calling routine is    }
  438. { telling us to dump the contents of the current buffer back out to the disk     } 
  439. procedure TBufferedFile.DumpBuffer;
  440. var writeResult : word;
  441. begin
  442.    {$ifndef _NDEBUG} Assert(isOpen, 'File not open yet', 19); {$endif}
  443.    { Go back to the beginning of the buffer and flush out our changes }
  444.    try
  445.       System.Seek(fileHandle, bufferFilePos);
  446.       System.BlockWrite(fileHandle, buffer^, bufferEnd, writeResult);
  447.    except
  448.       on EInOutError do raise;
  449.    end;
  450.    dirtyBuffer := false;
  451. end;
  452.  
  453.  
  454.  
  455. {-- Test Harness/Timing program --}
  456.  
  457. {$ifdef _TESTHARNESS}
  458. { (Tested) Used to exercise the file buffering routines above and compare }
  459. { them to the unbuffered equivalents.                                     }
  460. procedure TestFileBuff(
  461.             bufSize, recSize : word;
  462.             numIterations : longint;            
  463.             var oldCreateTime, oldCopyTime, oldReadTime, oldModifyTime : double;
  464.             var newCreateTime, newCopyTime, newReadTime, newModifyTime : double;
  465.             var benchWrite, benchRead : double); 
  466.  
  467. var 
  468.    bufferOut : array[0..10000] of char;                       
  469.    bigBuf : PChar;
  470.    tmpFile, tmpFile1 : file;
  471.    tempLong, i : longint;
  472.    begTime : TDateTime;
  473.    bufFile, bufFile1 : TBufferedFile;
  474.    amtWrote, amtRead : word;
  475.    seekPos : longint;
  476.  
  477. begin
  478.    { Limit to practical record size, could be bigger }
  479.    if (recSize > 10000) then recSize := 10000;
  480.    FillChar(bufferOut, sizeof(bufferOut), 'A');
  481.  
  482.    { Now create the file the new way }
  483.    begTime := Now;
  484.    bufFile := TBufferedFile.Create('\tFile-2.out', bufSize);
  485.    bufFile.Rewrite;
  486.    for i := 0 to numIterations do begin
  487.       bufFile.Write(bufferOut, recSize, amtWrote);
  488.    end;
  489.    bufFile.Close;
  490.    bufFile.Destroy;
  491.    newCreateTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  492.  
  493.    { Create the file the old fashion way }
  494.    begTime := Now;
  495.    Assign(tmpFile, '\tFile-1.out');
  496.    Rewrite(tmpFile,1);
  497.    for i := 0 to numIterations do begin
  498.       BlockWrite(tmpFile, bufferOut, recSize);
  499.    end;
  500.    Close(tmpFile);
  501.    oldCreateTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  502.  
  503.    { Copy the file w/ changes }
  504.    begTime := Now;
  505.    Assign(tmpFile, '\tFile-1.out');
  506.    Reset(tmpFile,1);
  507.    Assign(tmpFile1, '\tFile-11.out');
  508.    Rewrite(tmpFile1,1);
  509.    for i := 0 to numIterations do begin
  510.       BlockRead(tmpFile, bufferOut, recSize);
  511.       bufferOut[2] := 'Q';
  512.       bufferOut[20] := 'R';
  513.       bufferOut[30] := 'S';
  514.       BlockWrite(tmpFile1, bufferOut, recSize);
  515.    end;
  516.    Close(tmpFile);
  517.    Close(tmpFile1);
  518.    oldCopyTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  519.  
  520.    { New copy w/ Changes }
  521.    begTime := Now;
  522.    bufFile := TBufferedFile.Create('\tFile-2.out', bufSize);
  523.    bufFile.Reset;
  524.    bufFile1 := TBufferedFile.Create('\tFile-22.out', bufSize);
  525.    bufFile1.Rewrite;
  526.    for i := 0 to numIterations do begin
  527.       bufFile.Read(bufferOut, recSize, amtRead);
  528.       bufferOut[2] := 'Q';
  529.       bufferOut[20] := 'R';
  530.       bufferOut[30] := 'S';
  531.       bufFile1.Write(bufferOut, recSize, amtWrote);
  532.    end;
  533.    bufFile.Close;
  534.    bufFile.Destroy;
  535.    bufFile1.Close;
  536.    bufFile1.Destroy;
  537.    newCopyTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  538.  
  539.    { Read the file the old fashion way }
  540.    begTime := Now;
  541.    Assign(tmpFile, '\tFile-1.out');
  542.    Reset(tmpFile,1);
  543.    for i := 0 to numIterations do begin
  544.       BlockRead(tmpFile, bufferOut, recSize);
  545.    end;
  546.    Close(tmpFile);
  547.    oldReadTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  548.  
  549.    { Now Read the file the new way }
  550.    begTime := Now;
  551.    bufFile := TBufferedFile.Create('\tFile-2.out', bufSize);
  552.    bufFile.Reset;
  553.    for i := 0 to numIterations do begin
  554.       bufFile.Read(bufferOut, recSize, amtRead);
  555.    end;
  556.    bufFile.Close;
  557.    bufFile.Destroy;
  558.    newReadTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  559.  
  560.    { Unbuffered modify in place }
  561.    begTime := Now;
  562.    Assign(tmpFile, '\tFile-1.out');
  563.    Reset(tmpFile,1);
  564.    seekPos := 0;
  565.    for i := 0 to numIterations do begin
  566.       BlockRead(tmpFile, bufferOut, recSize);
  567.       Seek(tmpFile, seekPos);
  568.       bufferOut[1] := 'F'; bufferOut[2] := 'O';
  569.       BlockWrite(tmpFile, bufferOut, recSize);
  570.       inc(seekPos, recSize);
  571.    end;
  572.    Close(tmpFile);
  573.    oldModifyTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  574.  
  575.    { Buffered modify in place }
  576.    begTime := Now;
  577.    bufFile := TBufferedFile.Create('\tFile-2.out', bufSize);
  578.    bufFile.Reset;
  579.    seekPos := 0;
  580.    for i := 0 to numIterations do begin
  581.       bufFile.Read(bufferOut, recSize, amtRead);
  582.       bufFile.Seek(seekPos);
  583.       bufferOut[1] := 'F'; bufferOut[2] := 'O';
  584.       bufFile.Write(bufferOut, recSize, amtWrote);
  585.       inc(seekPos, recSize);
  586.    end;
  587.    bufFile.Close;
  588.    bufFile.Destroy;
  589.    newModifyTime := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  590.  
  591.    { Establish the best time possible for reading/ raw 64k at a time }
  592.    tempLong := numIterations * longint(recSize);
  593.    tempLong := tempLong div 65535;
  594.    GetMem(bigBuf, 65535);
  595.  
  596.    begTime := Now;
  597.    Assign(tmpFile, '\tFile-1.out');
  598.    Reset(tmpFile,1);
  599.    for i := 0 to tempLong-1 do begin
  600.       BlockRead(tmpFile, bigBuf^, 65535);
  601.    end;
  602.    Close(tmpFile);
  603.    benchRead := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  604.  
  605.    { Establish the best time possible for writing/ raw 64k at a time }
  606.    begTime := Now;
  607.    Assign(tmpFile, '\tFile-1.out');
  608.    Rewrite(tmpFile,1);
  609.    for i := 0 to tempLong do begin
  610.       BlockWrite(tmpFile, bigBuf^, 65535);
  611.    end;
  612.    Close(tmpFile);
  613.    benchWrite := ((Now - begTime) * 60.0 * 60.0 * 24.0);
  614.  
  615.    FreeMem(bigBuf, 65535);
  616.  
  617.    { Clean up all the misc files }
  618.    DeleteFile('\tFile-1.out');
  619.    DeleteFile('\tFile-2.out');
  620.    DeleteFile('\tFile-11.out');
  621.    DeleteFile('\tFile-22.out');
  622. end;
  623. {$endif}
  624.  
  625.  
  626. end.
  627.